
import rescuecore.*;
import rescuecore.objects.*;
import rescuecore.event.*;
import java.util.*;

public class SAMU extends PlatoonAgent {
	private int commId;
	private static int nextCommId=0;
	private String messageToTell=""; 
    private List<Humanoid> targets;
	private List<Building> buildings;	
	private List storedStructures;	
	private int countToRemove=0;
//	private int oldPosition = 0; 
//	private int oldPositionExtra = 0; 
//	private int stoppedCount =0;

    /**
       Construct a new SAMU
    */
    public SAMU() {
		super(RescueConstants.AGENT_TYPE_AMBULANCE_TEAM); // We need to specify that we can only be an ambulance team
		targets = new ArrayList<Humanoid>();
		buildings = new ArrayList<Building>();
		storedStructures = new ArrayList();
    }

    /**
       Get a reference the the AmbulanceTeam controlled by this agent
       @return the AmbulanceTeam controlled by this agent
    */
    private AmbulanceTeam me() {
		return (AmbulanceTeam)memory.lookup(id);
    }

    public void initialise(RescueObject[] knowledge, RescueObject self) {
		commId = ++nextCommId;
		// Add a memory listener so that we get informed about changes to humanoids
		super.initialise(knowledge,self);
		memory.addMemoryListener(new MemoryListener() {
				public void objectAdded(ObjectAddedEvent event) {
					RescueObject o = event.getObject();
					if (o.isHumanoid()) {
						Humanoid h = (Humanoid)o;
						// If the object is a buried humanoid, and we know the position of the humanoid, then add it to our target list
						if ( ((h.isBuried() || h.isDamaged()))  && h.isAlive() && memory.lookup(h.getPosition())!=null) {
							if (!targets.contains(h)) {
								targets.add(h);
							}
							messageToTell = new String ("V=" + h.getPosition() + ";" + messageToTell);
						}
					}
					else if (o.isRoad()) {
						if (((Road) o).isBlocked() && !((Road) o).hasFreeLines()) {
							messageToTell = new String (messageToTell + "S=" + ((Road)o).getID() + ";");
						}
					}
					else if (o.isBuilding()) {
						if (((Building)o).isOnFire()) {
							if(!storedStructures.contains(o)){
								storedStructures.add(o);
							}
							messageToTell = new String (messageToTell + "B=" + ((Building) o).getID() + ";") ;
						}
					}
				}
				public void objectChanged(ObjectChangedEvent event) {
					RescueObject o = event.getObject();
					if (o.isHumanoid()) {
						Humanoid h = (Humanoid)o;
						// If the object is a buried humanoid, and we know the position of the humanoid, then add it to our target list
						//if ((h.isBuried() || h.isDamaged()) && memory.lookup(h.getPosition())!=null) {
						if ((h.isBuried() || h.isDamaged()) && h.isAlive() && memory.lookup(h.getPosition())!=null) {
							if (!targets.contains(h)) {
								targets.add(h);
							}
							messageToTell = new String ("V=" + h.getPosition() + ";" + messageToTell);
						}
						else targets.remove(h); // Otherwise remove it
					}
				}
			});
		//		log("Initialised"); // Log a debugging message
    }

    public void sense() {
		if(timeStep % nextCommId == (commId-1) && messageToTell.length() > 0){
			
			tell(messageToTell.getBytes());
			//System.out.println( me() + " at step " + timeStep + ", telling: " + messageToTell);
			messageToTell = "";
		}


		SampleSearch.sortByDistance(targets,me(),memory);
		for (Humanoid next : targets) {
			if (next==me()) continue; // Ignore me
			// Am I transporting someone to a refuge?
			if (next.getPosition()==id) {
				// Am I at a refuge?
				if (getLocation() instanceof Refuge) {
					unload();
					//					System.out.println(this+" unloading");
					return;
				}
				else {
					// Plan a path to a refuge
					List<RescueObject> refuges = new ArrayList<RescueObject>();
					memory.getObjectsOfType(refuges,RescueConstants.TYPE_REFUGE);
					SampleSearch.sortByDistance(refuges,me(),memory);
					int[] path = SampleSearch.breadthFirstSearch(getLocation(),refuges.iterator().next(),memory);
					move(path);
					//					System.out.println(this+" heading for refuge");
					return;
				}
			}
			// Am I at the same location as this target (and not at a refuge)?
			if (!(getLocation() instanceof Refuge) && next.getPosition()==getPosition()) {
				//				System.out.println(this+" at same position as "+next);
				//				System.out.println(this+" buriedness = "+next.getBuriedness()+", damage="+next.getDamage());
				if (next.isBuried()) {
					// Yes! Dig him out
					//					System.out.println(this+" rescueing "+next);
					rescue(next);
					return;
				}
				else if (next.isDamaged()) {
					// Load him
					//					System.out.println(this+" loading "+next);
					load(next);
					return;
				}
			}
		}




//		if(getLocation().isRoad()) {
//			Road road = (Road) getLocation();
//			if(road.isBlocked() && !road.hasFreeLines() && getPosition() == oldPosition && oldPositionExtra == getPositionExtra()){
//				if(++stoppedCount > 5){
//					Collection<RescueObject> allRoads = memory.getObjectsOfType(RescueConstants.TYPE_ROAD); 
//					Road[] roads = new Road[allRoads.size()];
//					allRoads.toArray(roads);
//					Road r = (Road)roads[(int)(Math.random()*roads.length)]; 
//					int[] pathRoad = SampleSearch.breadthFirstSearch(getLocation(),r,memory);
//					if (pathRoad!=null) {
//						move(pathRoad);
//						return; 
//					}
//
//				}
//			}
//			else stoppedCount = 0;
//		}
//
//		oldPosition = getPosition();
//		oldPositionExtra = getPositionExtra();




		// Try to plan a path to the next best target
		for (Iterator<Humanoid> it = targets.iterator();it.hasNext();) {
			Humanoid next = it.next();
			RescueObject targetLocation = memory.lookup(next.getPosition());
			if (!next.isBuried() || targetLocation==null) {
				// If the target is not buried or we don't know its location then remove it from our target list
				it.remove();
				continue;
			}
			int[] path = SampleSearch.breadthFirstSearch(getLocation(),targetLocation,memory); // Find a path from my current location to the target's location
			if (path!=null) {
				move(path);
				return;
			}
		}

		
		
		SampleSearch.sortByDistance(buildings,me(),memory);
		for (Iterator<Building> it = buildings.iterator();it.hasNext();) {
			Building next = it.next();

			int[] path = SampleSearch.breadthFirstSearch(getLocation(), next ,memory); // Find a path from my current location to the target's location
			if (path!=null) {
				move(path);
				it.remove();
				return;
			}
			else it.remove();
		}


//		Collection<RescueObject> allBuildings = memory.getObjectsOfType(RescueConstants.TYPE_BUILDING); // Find all roads
//		Building[] buildings = new Building[allBuildings.size()];
//		allBuildings.toArray(buildings);
//		Building b = (Building)buildings[(int)(Math.random()*buildings.length)]; // Pick one at random
//		int [] entrances = b.getEntrances();
//		Node entrance = (Node)memory.lookup(entrances[(int)(Math.random()*entrances.length)]);
//		// Plan a path
//		int[] pathBuilding = SampleSearch.breadthFirstSearch(getLocation(),entrance,memory);
//		if (pathBuilding!=null) {
//			move(pathBuilding); // Move if the path is valiid
//			return;
//		}


		// We couldn't find a good target. Pick a random road and try moving there instead
		Collection<RescueObject> allRoads = memory.getObjectsOfType(RescueConstants.TYPE_ROAD); // Find all roads
		Road[] roads = new Road[allRoads.size()];
		allRoads.toArray(roads);
		Road r = (Road)roads[(int)(Math.random()*roads.length)]; // Pick one at random
		// Plan a path
		int[] pathRoad = SampleSearch.breadthFirstSearch(getLocation(),r,memory);
		if (pathRoad!=null) {
			//			System.out.println(this+" moving randomly");
			move(pathRoad); // Move if the path is valid
		}
    }

	protected boolean hearTell(int from, byte[] msg){
		if(from != id ) parserHumanoid(new String(msg));
		//System.out.println("[" + me() + "] "  + new String(msg) );
		return true;
	}

	protected synchronized void parserHumanoid(String msg){
		String [] result = msg.split(";");
		String received = new String();

		for (int i=0; i<result.length; i++){
			if(result[i].split("=")[0].startsWith("V")) {
				RescueObject o =  memory.lookup( (new  Integer(result[i].split("=")[1])).intValue() );
				if( !(o instanceof RescueObject)){
					System.out.println("[" + me() + "] NULL " + result[i].split("=")[1]);
					continue;				
				}

				if(o.isHumanoid()){
					Humanoid h = (Humanoid) o;
					if (h instanceof Humanoid && !targets.contains(h)) {
						targets.add(h);
						received = received + result[i].split("=")[1] + ";";
					}
					else System.out.println("[" + me() + "] ERRO EM " + result[i].split("=")[1]);
				}
				else if(o.isBuilding()){
					Building b = (Building) o;
					if (b instanceof Building && !buildings.contains(b)) {
						buildings.add(b);
						received = received + result[i].split("=")[1] + ";";
						System.out.println("[" + me() + "] Building " + result[i].split("=")[1]);
					}
					

				}
			}
		}
		if(received.length() > 0) System.out.println("[" + me() + "] Team Tasks received: " + received );
		
	}


	public boolean willListenHearTell(int from) {
		if(from == id) return false;
		else return true;
	}
	

	public boolean willListenHearSay(int from) {
		if(from == id) return false;
		else return true;
	}


	protected boolean hearSay(int from, byte [] msg){
		//System.out.println("Robocop escutou " + new String(msg) + " de " + from);
		return true;
	}
   

}
